using System;
using System.Collections.Generic;
using System.Text;
using System.Drawing;
using System.Drawing.Drawing2D;


namespace CSModeling
{
    public enum Illumination {None,SimpleFilling, PhoneModeling};
    public enum Shading {Phong, Gouraud, None };
    public enum Coloring {PureColor, PartiColor};
    partial class SMFModel
    {
        Random rnd = new Random(System.DateTime.Now.Second);
        public Vector3D[] _VectorList;
        private Vector3D[] _VectorNormalList;

        Face3D[] _FaceList;
        String _Version;
        Color _style = Color.Black;
        Matrix3D _RotateMatrix = new Matrix3D();
        Illumination _Filled = Illumination.None;
        Shading _Shade = Shading.None;
        Coloring _Color = Coloring.PartiColor;
        Vector3D _Shift = new Vector3D(300, 100, 0);
        Double _Zoom = 100;
        public PhongPara para = new PhongPara(new Vector3D(0, 0, 1), new Vector3D(0, 0, 1), 0, 255, 0, 255, 0, 255, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 0.5, 5);
        public SMFModel(String def, Color style, Coloring color)
        {
            _style = style;
            this._Color = color;
            String[] temp = def.Split("\r\n".ToCharArray());
            int VectorIndex = 0, FaceIndex = 0;
            foreach (String line in temp)
            {
                if (line.StartsWith("#$SMF"))
                {
                    _Version = line.Substring(line.IndexOf(' ') + 1);
                }
                else if (line.StartsWith("#$vertices"))
                {
                    _VectorList = new Vector3D[Convert.ToInt32(line.Substring(line.IndexOf(' ') + 1))];
                }
                else if (line.StartsWith("#$faces"))
                {
                    _FaceList = new Face3D[Convert.ToInt32(line.Substring(line.IndexOf(' ') + 1))];
                }
                else if (line.StartsWith("v"))
                {
                    String[] tmp4 = line.Split(' ');
                    String[] tmp2 = new string[3];
                    int Count = 0;
                    foreach (String tmp in tmp4)
                    {
                        if (!tmp.StartsWith("v") && tmp != "")
                        {
                            tmp2[Count] = tmp;
                            Count++;
                        }
                        if (Count == 3)
                            break;
                    }
                    _VectorList[VectorIndex] = new Vector3D(Convert.ToDouble(tmp2[0]), Convert.ToDouble(tmp2[1]), Convert.ToDouble(tmp2[2]));
                    VectorIndex++;
                }
                else if (line.StartsWith("f"))
                {
                    String[] tmp4 = line.Split(' ');
                    String[] tmp2 = new string[3];
                    int Count = 0;
                    foreach (String tmp in tmp4)
                    {
                        if (!tmp.StartsWith("f") && tmp != "")
                        {
                            tmp2[Count] = tmp;
                            Count++;
                        }
                        if (Count == 3)
                            break;
                    }
                    int shift = 0;
                    if (_Version.StartsWith("1.1"))
                        shift = 1;
                    //int tmp = rnd.Next(256);
                    
                    Color tmpcolor;
                    if (_Color == Coloring.PartiColor)
                    {
                        tmpcolor = Color.FromArgb(255, rnd.Next(255), rnd.Next(255), rnd.Next(255));
                    }
                    else
                    {
                        tmpcolor = style;
                    }
                    
                    _FaceList[FaceIndex] = new Face3D(Convert.ToInt32(tmp2[0]) - shift, Convert.ToInt32(tmp2[1]) - shift, 
                        Convert.ToInt32(tmp2[2]) - shift, FaceIndex, tmpcolor);
                    FaceIndex++;
                }
            }
        }
        public void SetColor(Color color, Graphics g, int Height, int Width)
        {
            _style = color;
            this.Refresh(g, Height, Width);
        }
        public void Zoom(int zoom, Graphics g, int Height, int Width)
        {
            _Zoom = Math.Pow(10, (double)zoom / 10);
            this.Refresh(g, Height, Width);
        }
        public void Shift(int x, int y, int z, Graphics g, int Height, int Width)
        {
            _Shift.X = x;
            _Shift.Y = y;
            _Shift.Z = z;
            this.Refresh(g, Height, Width);
        }
        public void Shift(int x, int y,  Graphics g, int Height, int Width)
        {
            _Shift.X = x;
            _Shift.Y = y;
            _Shift.Z = 0;
            this.Refresh(g, Height, Width);
        }
        public void SetIllumination(Illumination type, Graphics g, int Height, int Width)
        {
            if (type == Illumination.PhoneModeling)
            {
                _Filled = Illumination.PhoneModeling;
                _Shade = Shading.None;
                
            }
            else if (type == Illumination.SimpleFilling)
            {
                _Filled = Illumination.SimpleFilling;
                _Shade = Shading.None;
            }
            else
            {
                _Filled = Illumination.None;
                _Shade = Shading.None;
            }
            this.Refresh(g, Height, Width);
        }
        public void SetShading(Shading type, Graphics g, int Height, int Width)
        {
            if (_Filled == Illumination.PhoneModeling)
            {
                if (type == Shading.Phong)
                {
                    _Shade = Shading.Phong;
                }
                else if (type == Shading.Gouraud)
                {
                    _Shade = Shading.Gouraud;
                }
                else
                    _Shade = Shading.None;
            }
            this.Refresh(g, Height, Width);
        }
        public void SetColor(Coloring color, Color style, Graphics g, int Height, int Width)
        {
            foreach (Face3D face in _FaceList)
            {
                if (color == Coloring.PureColor)
                    face.Style = style;
                else
                    face.Style = Color.FromArgb(255, rnd.Next(255), rnd.Next(255), rnd.Next(255));
            }
            this.Refresh(g, Height, Width);
        }
        public void Rotate(Double angleX, Double angleY, Double angleZ, Graphics g, int Height, int Width)
        {
            this._RotateMatrix = Matrix3DMath.RotateX(Matrix3DMath.DEGtoRAD(angleX)) * Matrix3DMath.RotateY(Matrix3DMath.DEGtoRAD(angleY)) * Matrix3DMath.RotateZ(Matrix3DMath.DEGtoRAD(angleZ));
            this.Refresh(g, Height, Width);
        }
        public void RebuildVectorNormals()
        {
            if (_VectorNormalList != null)
                return;
            else
            {
                _VectorNormalList = new Vector3D[_VectorList.Length];
                int[] FaceCount = new int[_VectorList.Length];
                Vector3D NormalVector;
                foreach (Face3D face in _FaceList)
                {
                    NormalVector = this.RetrieveNormalVector(face);
                    foreach (int i in face.List)
                    {
                        FaceCount[i]++;
                        if (_VectorNormalList[i] == null)
                            _VectorNormalList[i] = new Vector3D();
                        _VectorNormalList[i] += NormalVector;
                    }
                }
                for (int i = 0; i < _VectorNormalList.Length; i++)
                {
                    if (_VectorNormalList[i] != null)
                    _VectorNormalList[i] = _VectorNormalList[i] / FaceCount[i];
                }
            }
        }
        private Vector3D RetrieveVector(int index)
        {
            return (_RotateMatrix * _VectorList[index]) * _Zoom + _Shift;
        }
        private Vector3D RetrieveNormalVector(Face3D face)
        {
            Vector3D v1 = RetrieveVector(face.List[1]) - RetrieveVector(face.List[0]);
            Vector3D v2 = RetrieveVector(face.List[2]) - RetrieveVector(face.List[0]);
            Vector3D res = v1 ^ v2;
            res = res / Math.Sqrt(res * res);
            return res;
        }
        private Vector3D RetrieveNormalVector(int Vector)
        {
            if (_VectorNormalList == null)
            {
                return new Vector3D();
            }
            else
            {
                return _VectorNormalList[Vector];
            }
        }
    }
}
